/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.hiof.moraa.server.dao;

import com.hiof.moraa.server.service.model.LiveLocationFeed;
import com.hiof.moraa.mapping.TblAthlete;
import com.hiof.moraa.mapping.TblAthleteLiveLocation;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

/**
 *
 * @author Bergy
 */
public class HibernateAthleteLiveLocationDAOImp implements AthleteLiveLocationDAO {

    private SessionFactory factory;

    public SessionFactory getFactory() {
        return factory;
    }

    public void setFactory(SessionFactory factory) {
        this.factory = factory;
    }

    @Override
    public LiveLocationFeed insertAthleteLiveLocationFeed(int athleteId, double lat, double lng, double height, double speed, Timestamp timestamp) {
        TblAthleteLiveLocation athleteLiveLocation = new TblAthleteLiveLocation();
        try {
            TblAthlete athlete = (TblAthlete) factory.getCurrentSession().get(TblAthlete.class, athleteId);
            athleteLiveLocation.setLat(lat);
            athleteLiveLocation.setLng(lng);
            athleteLiveLocation.setHeight(height);
            athleteLiveLocation.setSpeed(speed);
            athleteLiveLocation.setTblAthlete(athlete);
            athleteLiveLocation.setTimeStamp(timestamp);

            factory.getCurrentSession().save(athleteLiveLocation);
        } catch (HibernateException e) {
            Logger.getLogger(HibernateAthleteLiveLocationDAOImp.class.getName()).log(Level.SEVERE, "Hibernate Exception Occured", e);
        }

        LiveLocationFeed liveLocationFeed = convert2LiveLocationFeed(athleteLiveLocation);
        return liveLocationFeed;
    }

    @Override
    public List<LiveLocationFeed> getLatestLiveLocationFeedOfAllAthlete(int routeId) {
        Session session = factory.getCurrentSession();
        List<LiveLocationFeed> result = new ArrayList<LiveLocationFeed>();
        String sql = new StringBuilder().append("select * from ( \n").append("    select athlete_id, max(timeStamp) as timeStamp \n").append("    from tbl_athlete_live_location, tbl_athlete \n").append("    where tbl_athlete.route_id = :routeId and tbl_athlete.id = tbl_athlete_live_location.athlete_id \n").append("    group by athlete_id \n").append(") as groupTable inner join tbl_athlete_live_location as athlete \n").append("on athlete.athlete_id = groupTable.athlete_id and athlete.timeStamp = groupTable.timeStamp; \n").toString();

        Query query = session.createSQLQuery(sql).addEntity(TblAthleteLiveLocation.class);
        List liveLocations = query.setInteger("routeId", routeId).list();

        for (Iterator it = liveLocations.iterator(); it.hasNext();) {
            TblAthleteLiveLocation liveLocation = (TblAthleteLiveLocation) it.next();
            result.add(convert2LiveLocationFeed(liveLocation));
        }
        return result;
    }

    @Override
    public List<LiveLocationFeed> getLatestLiveLocationFeedOfAthleteInOneRoute(int routeId, int numOfFeed) {
        Session session = factory.getCurrentSession();

        String hql = "from TblAthleteLiveLocation location where location.tblAthlete.tblRoute.id = :routeId "
                + "order by location.timeStamp desc";
        Query query = session.createQuery(hql);
        query.setInteger("routeId", routeId);
        query.setMaxResults(numOfFeed);
        List<TblAthleteLiveLocation> athleteLiveLocations = query.list();

        List<LiveLocationFeed> result = fetchToLiveMediaLocationList(athleteLiveLocations);
        athleteLiveLocations.clear();
        return result;
    }

    @Override
    public List<LiveLocationFeed> getLatestLiveLocationFeedOfOneUserInOneRoute(String username, int routeId, int numOfLiveLocationFeed) {
        Session session = factory.getCurrentSession();

        String hql = "from TblAthleteLiveLocation location where location.tblAthlete.tblUser.username = :username and location.tblAthlete.tblRoute.id = :routeId "
                + "order by location.timeStamp desc";
        Query query = session.createQuery(hql);
        query.setString("username", username);
        query.setInteger("routeId", routeId);
        query.setMaxResults(numOfLiveLocationFeed);
        List<TblAthleteLiveLocation> athleteLiveLocations = query.list();

        List<LiveLocationFeed> result = fetchToLiveMediaLocationList(athleteLiveLocations);
        athleteLiveLocations.clear();
        return result;
    }

    @Override
    public LiveLocationFeed getLatestLiveLocationFeedOfOneAthlete(int athleteId) {
        Session session = factory.getCurrentSession();

        String hql = "from TblAthleteLiveLocation location where location.tblAthlete.id = :athleteId "
                + "order by location.timeStamp desc";
        Query query = session.createQuery(hql);
        query.setInteger("athleteId", athleteId);
        query.setMaxResults(1);
        TblAthleteLiveLocation athleteLiveLocation = (TblAthleteLiveLocation) query.uniqueResult();
        return convert2LiveLocationFeed(athleteLiveLocation);
    }

    @Override
    public List<LiveLocationFeed> getLiveLocationFeedOfAthleteByUsername(String username, int routeId) {
        try {
            Session session = factory.getCurrentSession();

            String hql = "from TblAthleteLiveLocation location where location.tblAthlete.tblUser.username = :username and location.tblAthlete.tblRoute.id = :routeId "
                    + "order by location.timeStamp desc";
            Query query = session.createQuery(hql);
            query.setString("username", username);
            query.setInteger("routeId", routeId);
            List<TblAthleteLiveLocation> athleteLiveLocations = query.list();

            List<LiveLocationFeed> result = fetchToLiveMediaLocationList(athleteLiveLocations);
            athleteLiveLocations.clear();
            return result;
        } catch (Exception ex) {
            return new ArrayList<LiveLocationFeed>();
        }
    }

    private List<LiveLocationFeed> fetchToLiveMediaLocationList(List<TblAthleteLiveLocation> athleteLiveLocations) {
        List<LiveLocationFeed> result = new ArrayList<LiveLocationFeed>();
        for (TblAthleteLiveLocation location : athleteLiveLocations) {
            result.add(convert2LiveLocationFeed(location));
        }
        return result;
    }

    private LiveLocationFeed convert2LiveLocationFeed(TblAthleteLiveLocation athleteLiveLocation) {
        if(athleteLiveLocation == null)
            return null;
        LiveLocationFeed liveLocationFeed = new LiveLocationFeed(
                athleteLiveLocation.getTblAthlete().getTblUser().getId(),
                athleteLiveLocation.getTblAthlete().getTblUser().getUsername(),
                athleteLiveLocation.getTblAthlete().getTblUser().getFirstName() + " " + athleteLiveLocation.getTblAthlete().getTblUser().getLastName(),
                athleteLiveLocation.getTblAthlete().getTblUser().getProfilePicture(),
                athleteLiveLocation.getTimeStamp(),
                athleteLiveLocation.getTblAthlete().getAttendantCode(),
                athleteLiveLocation.getLat(), athleteLiveLocation.getLng(),
                athleteLiveLocation.getHeight(), athleteLiveLocation.getSpeed());
        return liveLocationFeed;
    }
}
